home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / Terminal 2.2 / Project / Sources / Main.c < prev    next >
Text File  |  1992-01-17  |  19KB  |  819 lines

  1. /*
  2.     Terminal 2.2
  3.     "Main.c"
  4. */
  5.  
  6. #ifdef THINK_C
  7. #include "MacHeaders"
  8. #endif
  9. #ifdef applec
  10. #pragma load ":(Objects):MacHeadersMPW"
  11. #pragma segment Main
  12. #endif
  13.  
  14. #include "Text.h"
  15. #include "Main.h"
  16. #include "Strings.h"
  17. #include "Utilities.h"
  18. #include "Document.h"
  19. #include "File.h"
  20. #include "Options.h"
  21. #include "Scroll.h"
  22. #include "Port.h"
  23. #include "FormatStr.h"
  24. #include "Macros.h"
  25. #include "CancelDialog.h"
  26. #include "Crc.h"
  27.  
  28. #define CAN        0x18    /* Cntrl-X */
  29.  
  30. /* ----- Globals ------------------------------------------------------- */
  31.  
  32. SysEnvRec        Mac;                /* Machine information */
  33. Boolean            WNE;                /* WaitNextEvent() flag */
  34. Boolean            Background;            /* In background flag */
  35. DocumentPeek    TerminalWindow;        /* Terminal window */
  36. Options            Settings;            /* Current options */
  37. Byte            EmptyStr[] = "";    /* Often needed empty string */
  38. OSType            TEXT = 'TEXT';        /* Text file type */
  39. Handle            KCHR;                /* 'KCHR' resource */
  40. Types            Application;        /* Application information */
  41. Boolean            Abort = FALSE;        /* Abort flag */
  42. Boolean            Busy = FALSE;        /* Transmit in progress flag */
  43. short            SendFileRef = 0;    /* Send file reference number */
  44. Boolean            Sending = FALSE;    /* Sending in progress */
  45. short            Transfer = 0;        /* File transfer in progress */
  46. Configuration    Config;                /* Configuration parameters */
  47. Boolean            Control_X = FALSE;    /* Control-X abort flag */
  48. Handle            MacrosText = 0;        /* Macros text */
  49. Boolean            MFmemory;            /* MultiFinder temporary memory */
  50. Boolean            DTR = FALSE;        /* Current state of DTR output */
  51. #ifdef USECTB
  52. Boolean            CTB;                /* Communications Tool Box flag */
  53. #endif
  54.  
  55. /* ----- Display error alert ------------------------------------------- */
  56.  
  57. void Error(
  58.     register short code,
  59.     register Byte *text)
  60. {
  61.     Byte message[256];
  62.  
  63.     FormatStr(message, (Byte *)"\p%s%i %s", MyString(STR_M, M_ERROR),
  64.         code, text);
  65.     if (TerminalWindow) {
  66.         SysBeep(1);
  67.         MakeMessage(TerminalWindow, message);
  68.     } else {
  69.         ParamText(message, EmptyStr, EmptyStr, EmptyStr);
  70.         CenterDialog('ALRT', ALRT_ERROR);
  71.         Alert(ALRT_ERROR, 0);
  72.     }
  73. }
  74.  
  75. /* ----- See if window is document window ------------------------------ */
  76.  
  77. Boolean IsDocument(register WindowPtr window)
  78. {
  79.     return window && ((WindowPeek)window)->windowKind == userKind;
  80. }
  81.  
  82. /* ----- See if window is system window -------------------------------- */
  83.  
  84. Boolean IsSystem(register WindowPtr window)
  85. {
  86.     return window && ((WindowPeek)window)->windowKind < 0;
  87. }
  88.  
  89. /* ----- Quit ---------------------------------------------------------- */
  90.  
  91. static void Terminate(void)
  92. {
  93.     register short err;
  94.     register Byte *name;
  95.     short r;
  96.     long count;
  97.     Point position;
  98.  
  99.     SerialDropDTR(Settings.dropDTR);
  100.     SerialClose();
  101.     if (SendFileRef)            /* Close send file if necessary */
  102.         FSClose(SendFileRef);
  103.     if (TerminalWindow->file)    /* Close capture file if necessary */
  104.         TextCapture(0);
  105.     DisposPtr((Ptr)TerminalWindow->buf.text);
  106.     position = topLeft(((GrafPtr)TerminalWindow)->portRect);
  107.     SetPort((GrafPtr)TerminalWindow);
  108.     LocalToGlobal(&position);
  109.     if (position.h != Settings.terminalWindow.h ||
  110.             position.v != Settings.terminalWindow.v ) {
  111.         Settings.terminalWindow = position;
  112.         Settings.dirty = TRUE;
  113.     }
  114.     DisposeWindow((WindowPtr)TerminalWindow);
  115.     if (MacrosText)
  116.         DisposHandle(MacrosText);
  117.  
  118.     /* Save options if necessary */
  119.  
  120.     if (Settings.dirty) {
  121.         if ((err = OpenFile(Settings.scriptVolume,
  122.                 Settings.scriptDirectory,
  123.                 name = MyString(STR_G, G_SETTINGS), &r)) == fnfErr) {
  124.             if (!(err = CreateFile(Settings.scriptVolume,
  125.                     Settings.scriptDirectory, name,
  126.                     Application.signature, Application.otype)))
  127.                 err = OpenFile(Settings.scriptVolume,
  128.                         Settings.scriptDirectory,
  129.                     name, &r);
  130.         }
  131.         if (!err) {
  132.             Settings.version = SETTINGS;
  133.             Settings.crc = CalcCRC((Byte *)&Settings + sizeof(short),
  134.                 sizeof(Settings) - sizeof(short), 0);
  135.             count = sizeof(Settings);
  136.             err = FSWrite(r, &count, (Ptr)&Settings);
  137.             FSClose(r);
  138.             FlushVol(0, Mac.sysVRefNum);
  139.         }
  140.         if (err)
  141.             Error(err, EmptyStr);
  142.     }
  143.     ExitToShell();
  144. }
  145.  
  146. /* ----- Adjust menus -------------------------------------------------- */
  147.  
  148. static void AdjustMenus(void)
  149. {
  150.     register MenuHandle menu;
  151.     register Boolean empty =
  152.         TerminalWindow->buf.newChar == TerminalWindow->buf.firstChar;
  153.  
  154.     menu = GetMHandle(FILE);
  155.     if (Transfer) {
  156.         DisableItem(menu, SCREEN);
  157.         DisableItem(menu, CAPTURE);
  158.         DisableItem(menu, SEND);
  159.         switch (Transfer) {
  160.             case Transfer_Rx:
  161.                 EnableItem(menu, RECEIVE);    /* To cancel receive */
  162.                 DisableItem(menu, TRANSMIT);
  163.                 break;
  164.             case Transfer_Tx:
  165.                 DisableItem(menu, RECEIVE);
  166.                 EnableItem(menu, TRANSMIT);    /* To cancel transmit */
  167.                 break;
  168.             case Transfer_B:
  169.                 DisableItem(menu, RECEIVE);
  170.                 DisableItem(menu, TRANSMIT);
  171.         }
  172.         DisableItem(menu, MAKE);
  173.         DisableItem(menu, EXTRACT);
  174.         DisableItem(menu, KISS);
  175.         DisableItem(menu, QUIT);
  176.     } else {
  177.         if (empty)
  178.             DisableItem(menu, SCREEN);
  179.         else
  180.             EnableItem(menu, SCREEN);
  181.         EnableItem(menu, CAPTURE);
  182.         EnableItem(menu, SEND);
  183.         EnableItem(menu, RECEIVE);
  184.         EnableItem(menu, TRANSMIT);
  185.         EnableItem(menu, MAKE);
  186.         EnableItem(menu, EXTRACT);
  187.         EnableItem(menu, KISS);
  188.         EnableItem(menu, QUIT);
  189.     }
  190.  
  191.     menu = GetMHandle(EDIT);
  192.     if (Transfer) {
  193.         DisableItem(menu, RESET);
  194.         EnableItem(menu, SHOWPW);
  195.         DisableItem(menu, DEBLOCK);
  196.     } else {
  197.         if (empty)
  198.             DisableItem(menu, RESET);
  199.         else
  200.             EnableItem(menu, RESET);
  201.         DisableItem(menu, SHOWPW);
  202.         EnableItem(menu, DEBLOCK);
  203.     }
  204.     if (DTR) {
  205.         EnableItem(menu, DTRDROP);
  206.         DisableItem(menu, DTRASSERT);
  207.     } else {
  208.         DisableItem(menu, DTRDROP);
  209.         EnableItem(menu, DTRASSERT);
  210.     }
  211.     if (IsSystem(FrontWindow())) {
  212.         EnableItem(menu, UNDO);
  213.         EnableItem(menu, CUT);
  214.         EnableItem(menu, COPY);
  215.         EnableItem(menu, PASTE);
  216.         EnableItem(menu, CLEAR);
  217.     } else {
  218.         long offset;
  219.         DisableItem(menu, UNDO);
  220.         DisableItem(menu, CUT);
  221.         DisableItem(menu, COPY);
  222.         if (Transfer || GetScrap(0, TEXT, &offset) <= 0)
  223.             DisableItem(menu, PASTE);
  224.         else
  225.             EnableItem(menu, PASTE);
  226.         DisableItem(menu, CLEAR);
  227.     }
  228.  
  229.     menu = GetMHandle(OPTIONS);
  230.     if (Transfer)
  231.         DisableItem(menu, 0);
  232.     else
  233.         EnableItem(menu, 0);
  234.  
  235.     menu = GetMHandle(SCRIPT);
  236.     if (Transfer)
  237.         DisableItem(menu, 0);
  238.     else
  239.         EnableItem(menu, 0);
  240.  
  241.     menu = GetMHandle(MACRO);
  242.     if (Transfer)
  243.         DisableItem(menu, 0);
  244.     else
  245.         EnableItem(menu, 0);
  246. }
  247.  
  248. /* ----- Handle menu commands ------------------------------------------ */
  249.  
  250. static void DoMenuCommand(
  251.     register long menuResult,
  252.     short options)
  253. {
  254.     register short menuItem;
  255.     Str255 daName;
  256.  
  257.     menuItem = LoWrd(menuResult);
  258.     switch(HiWrd(menuResult)) {
  259.         case APPLE:
  260.             switch(menuItem) {
  261.                 case ABOUT:
  262.                     About(options);
  263.                     UnloadSeg(About);
  264.                     break;
  265.                 default:
  266.                     GetItem(GetMHandle(APPLE), menuItem, (Byte *)&daName);
  267.                     OpenDeskAcc((Byte *)&daName);
  268.                     break;
  269.             }
  270.             break;
  271.         case FILE:
  272.             switch(menuItem) {
  273.                 case SCREEN:        /* Save screen buffer */
  274.                     SaveBuffer(options);
  275.                     break;
  276.                 case CAPTURE:        /* Capture to text file */
  277.                     TextCapture(options);
  278.                     break;
  279.                 case SEND:            /* Send text file */
  280.                     HiliteMenu(0);
  281.                     SendText();
  282.                     return;
  283.                 case RECEIVE:        /* Receive file */
  284.                     HiliteMenu(0);
  285.                     FileReceive();
  286.                     return;
  287.                 case TRANSMIT:        /* Transmit file */
  288.                     HiliteMenu(0);
  289.                     FileTransmit();
  290.                     return;
  291.                 case MAKE:            /* Make MacBinary file */
  292.                     Make();
  293.                     break;
  294.                 case EXTRACT:        /* Extract from MacBinary file */
  295.                     Extract();
  296.                     break;
  297.                 case KISS:            /* Kiss script file file */
  298.                     Kiss(options);
  299.                     break;
  300.                 case QUIT:
  301.                     HiliteMenu(0);
  302.                     Terminate();
  303.                     return;
  304.             }
  305.             break;
  306.         case EDIT:
  307.             if (!SystemEdit(menuItem-1)) {
  308.                 switch(menuItem) {
  309.                     case PASTE:        /* Send TEXT from scrap */
  310.                         HiliteMenu(0);
  311.                         SendScrap();
  312.                         return;
  313.                     case RESET:        /* Clear capture buffer */
  314.                         ClearBuffer();
  315.                         break;
  316.                     case SHOWPW:    /* Show progress window */
  317.                         SelectCancelDialog();
  318.                         break;
  319.                     case DEBLOCK:    /* Deblock send after XOFF/CTS */
  320.                         Sending = FALSE;
  321.                         SerialAbort();
  322.                         break;
  323.                     case DTRDROP:    /* Drop DTR */
  324.                         SerialDTR(FALSE);
  325.                         break;
  326.                     case DTRASSERT:    /* Assert DTR */
  327.                         SerialDTR(TRUE);
  328.                         break;
  329.                     case CTSCHECK:    /* Check CTS */
  330.                         {
  331.                             Byte s[80];
  332.                             MakeMessage(TerminalWindow,
  333.                                 FormatStr(s, (Byte *)"\pCTS=%i", SerialCTS()));
  334.                         }
  335.                         break;
  336.                 }
  337.             }
  338.             break;
  339.         case OPTIONS:
  340.             switch(menuItem) {
  341.                 case PORT:
  342.                     PortOptions();
  343.                     UnloadSeg(PortOptions);
  344.                     break;
  345.                 case TEXTSEND:
  346.                     SendOptions();
  347.                     UnloadSeg(SendOptions);
  348.                     break;
  349.                 case TERMINAL:
  350.                     TerminalOptions();
  351.                     UnloadSeg(TerminalOptions);
  352.                     break;
  353.                 case OTHER:
  354.                     OtherOptions();
  355.                     UnloadSeg(OtherOptions);
  356.                     break;
  357.                 case TRANSFER:
  358.                     ProtocolOptions();
  359.                     UnloadSeg(ProtocolOptions);
  360.                     break;
  361.                 case XYOPTIONS:
  362.                     XYOptions();
  363.                     UnloadSeg(XYOptions);
  364.                     break;
  365.                 case ZOPTIONS:
  366.                     ZOptions();
  367.                     UnloadSeg(ZOptions);
  368.                     break;
  369.             }
  370.             break;
  371.         case SCRIPT:
  372.             HiliteMenu(0);
  373.             if (menuItem == DOSCRIPT) {
  374.                 if (RunScript(0, 0, 0, menuItem))
  375.                     Terminate();
  376.                 return;
  377.             }
  378.             if (DoMenuScript(menuItem))
  379.                 Terminate();
  380.             return;
  381.         case MACRO:
  382.             if (menuItem == DOMACRO) {
  383.                 short err;
  384.                 if (err = LoadMacros(0, 0, 0))
  385.                     Error(err, EmptyStr);
  386.             } else {
  387.                 HiliteMenu(0);
  388.                 DoMacro(menuItem, (options & (optionKey | shiftKey)) != 0);
  389.                 return;
  390.             }
  391.     }
  392.     HiliteMenu(0);
  393. }
  394.  
  395. /* ----- Handle new event ---------------------------------------------- */
  396.  
  397. #define SuspendResume    1
  398. #define ResumeMask        1
  399.  
  400. void DoEvent(register EventRecord *event)
  401. {
  402.     register short part;
  403.     register Byte key;            /* ASCII key code */
  404.     register short code;        /* Virtual key code */
  405.     long state;                    /* Used by KeyTrans() */
  406.     WindowPtr window;
  407.  
  408.     switch(event->what) {
  409.         case mouseDown:
  410.             switch(part = FindWindow(event->where, &window)) {
  411.                 case inMenuBar:
  412.                     AdjustMenus();
  413.                     DoMenuCommand(MenuSelect(event->where),
  414.                         event->modifiers);
  415.                     break;
  416.                 case inSysWindow:
  417.                     SystemClick(event, window);
  418.                     break;
  419.                 case inContent:
  420.                     if (window != FrontWindow())
  421.                         SelectWindow(window);
  422.                     else {
  423.                         if (IsDocument(window)) {
  424.                             SetPort(window);
  425.                             GlobalToLocal(&event->where);
  426.                             DocumentClick((DocumentPeek)window,
  427.                                 event->where, event->modifiers);
  428.                         }
  429.                     }
  430.                     break;
  431.                 case inDrag:
  432.                     DragWindow(window, event->where, &QD(screenBits.bounds));
  433.                     break;
  434.                 case inGoAway:
  435.                     /* Quit if close box clicked in document window */
  436.                     if (TrackGoAway(window, event->where)) {
  437.                         if (IsDocument(window)) {
  438.                             if (Transfer)
  439.                                 SysBeep(1);
  440.                             else
  441.                                 Terminate();
  442.                         }
  443.                         if (IsSystem(window))
  444.                             CloseDeskAcc(((WindowPeek)window)->windowKind);
  445.                     }
  446.                     break;
  447.                 }
  448.                 break;
  449.             case keyDown:
  450.             case autoKey:
  451.                 if (IsSystem(FrontWindow()))
  452.                     break;
  453.                 key = event->message & charCodeMask;
  454.                 /* Menu commands are not available if the command key
  455.                 is used as control key */
  456.                 if (Settings.ctrl != 2 && (event->modifiers & cmdKey)) {
  457.                     if (event->what == keyDown) {
  458.                         AdjustMenus();
  459.                         DoMenuCommand(MenuKey(key), event->modifiers);
  460.                     }
  461.                     break;
  462.                 }
  463.                 /* Ignore key strokes if file transfer is in progress,
  464.                 or if terminal window is not frontmost */
  465.                 if (Transfer || !IsDocument(FrontWindow()))
  466.                     break;
  467.                 /* Use option key as control key, if this option is set */
  468.                 if (Settings.ctrl == 1 && (event->modifiers & optionKey) && KCHR) {
  469.                     code = (event->message >> 8) & 0x7F;
  470.                     if (event->modifiers & shiftKey)
  471.                         code |= 0x0200;
  472.                     state = 0;
  473.                     LoadResource(KCHR);
  474.                     if (*KCHR)
  475.                         key = KeyTrans(*KCHR, code, &state) & 0x1F;
  476.                 } else
  477.                     /* Use option key as control key, if this option is set */
  478.                     if (Settings.ctrl == 2 && (event->modifiers & cmdKey))
  479.                         key &= 0x1F;
  480.                 NewKey(key);
  481.                 break;
  482.             case activateEvt:
  483.                 if (IsDocument((WindowPtr)event->message))
  484.                     ActivateDocument((DocumentPeek)event->message,
  485.                         event->modifiers & activeFlag);
  486.                 break;
  487.             case updateEvt:
  488.                 if (IsDocument((WindowPtr)event->message)) {
  489.                     BeginUpdate((WindowPtr)event->message);
  490.                     DrawDocument((DocumentPeek)event->message, 0);
  491.                     DrawControls((WindowPtr)event->message);
  492.                     EndUpdate((WindowPtr)event->message);
  493.                 }
  494.                 break;
  495.             case diskEvt:
  496.                 if (HiWord(event->message) != noErr) {
  497.                     static Point where = { 80, 80 };
  498.                     DIBadMount(where, event->message);
  499.                 }
  500.                 break;
  501.             case app4Evt:
  502.                 if (((unsigned long)event->message >> 24)==SuspendResume) {
  503.                     window = FrontWindow();
  504.                     if (event->message & ResumeMask) {
  505.                         Background = FALSE;
  506.                         if (IsDocument(window)) {
  507.                             HiliteWindow(window, TRUE);
  508.                             ActivateDocument((DocumentPeek)window, TRUE);
  509.                         }
  510.                     } else {
  511.                         Background = TRUE;
  512.                         if (IsDocument(window)) {
  513.                             HiliteWindow(window, FALSE);
  514.                             ActivateDocument((DocumentPeek)window, FALSE);
  515.                         }
  516.                     }
  517.                 }
  518.                 break;
  519.         }
  520. }
  521.  
  522. /* ----- Check for ctrl-X (abort sending) ------------------------------ */
  523.  
  524. static void AbortCheck(
  525.     register Byte *buffer,
  526.     register long count)
  527. {
  528.     static short can = 0;
  529.  
  530.     while (count--) {
  531.         *buffer &= 0x7F;            /* Strip bit 7 */
  532.         if (*buffer++ == CAN) {        /* Check for control-X */
  533.             if (can == 4) {            /* 5th consecutive control-X */
  534.                 SerialAbort();
  535.                 Sending = FALSE;
  536.                 Control_X = TRUE;
  537.             } else
  538.                 ++can;
  539.         } else
  540.             can = 0;
  541.     }
  542. }
  543.  
  544. /* ----- Strip BS characters from string ------------------------------- */
  545.  
  546. static void StripBS(register Byte *s)
  547. {
  548.     register Byte t[256];
  549.     register Byte *p, *q;
  550.     register Byte c;
  551.     register short n;
  552.  
  553.     n = *s;
  554.     p = s + 1;
  555.     q = t + 1;
  556.     while (n--) {
  557.         if ((c = *p++) == Settings.backspace) {
  558.             if (q == t + 1)
  559.                 break;
  560.             --q;
  561.         } else
  562.             *q++ = c;
  563.     }
  564.     *t = q - (t + 1);
  565.     memcpy(s, t, *t + 1);
  566. }
  567.  
  568. /* ----- Quick event check --------------------------------------------- */
  569.  
  570. void CheckEvents(void)
  571. {
  572.     register long count;
  573.     register Byte buffer[256];
  574.     EventRecord event;
  575.  
  576.     /* Make sure events and receive buffer are checked at least once */
  577.  
  578.     do {
  579.  
  580.         /* While transmitting check Mac events */
  581.  
  582.         do {
  583.             if (WNE)
  584.                 WaitNextEvent(everyEvent, &event, 0, 0);
  585.             else {
  586.                 SystemTask();
  587.                 GetNextEvent(everyEvent, &event);
  588.             }
  589.             DoEvent(&event);
  590.         } while (Busy);
  591.  
  592.         /* If transmission finished see if something received */
  593.  
  594.         if (count = SerialRead(buffer, sizeof(buffer))) {
  595.             AbortCheck(buffer, count);
  596.             if (Settings.echo)
  597.                 SerialSend(buffer, count, &Busy);
  598.             if (Settings.save)
  599.                 NewCharacters(buffer, count, FALSE);
  600.         }
  601.  
  602.     } while (Busy);
  603.     /* Only return if no more transmission is going on */
  604. }
  605.  
  606. /* ----- Universal main event loop ------------------------------------- */
  607.  
  608. short Loop(
  609.     register long timeout,    /* Timeout in ticks (0 for no timeout) */
  610.     Byte *string,            /* Prompt string (1) or line (2) */
  611.     register short mode)    /* 1: wait for prompt, 2: return next line */
  612. {
  613.     register long count;        /* Number of characters received */
  614.     register short code = -1;    /* Return code */
  615.     Byte buffer[256];            /* Receive buffer */
  616.     EventRecord event;
  617.     register Byte *s, *p, *max;
  618.     register Byte c;
  619.  
  620.     if (timeout)
  621.         timeout += Ticks;
  622.     Abort = FALSE;
  623.     if (string) {
  624.         switch (mode) {
  625.             case 1:    /* Prompt mode */
  626.                 if (*string)
  627.                     max = string + *string;
  628.                 else
  629.                     mode = 0;
  630.                 break;
  631.             case 2:    /* Line mode */
  632.                 max = string + 255;
  633.                 break;
  634.         }
  635.         s = string + 1;
  636.     } else
  637.         mode = 0;
  638.  
  639.     /* Make sure events and receive buffer are checked at least once */
  640.  
  641.     do {
  642.  
  643.         /* Check for and handle Mac events */
  644.  
  645.         do {
  646.             if (WNE)
  647.                 WaitNextEvent(everyEvent, &event, 0, 0);
  648.             else {
  649.                 SystemTask();
  650.                 GetNextEvent(everyEvent, &event);
  651.             }
  652.             DoEvent(&event);
  653.         } while (Busy);
  654.  
  655.         /* Check receive buffer */
  656.  
  657.         if (code < 0 && (count = SerialRead(buffer, sizeof(buffer)))) {
  658.             AbortCheck(buffer, count);
  659.             if (Settings.echo)
  660.                 SerialSend(buffer, count, &Busy);
  661.             if (Settings.save)
  662.                 NewCharacters(buffer, count, TRUE);
  663.             switch (mode) {
  664.                 case 1:    /* Prompt mode */
  665.                     p = buffer;
  666.                     while (count--)
  667.                         if ((*p++ & 0x7F) == *s) {
  668.                             if (s >= max) {
  669.                                 code = FINE;
  670.                                 break;    /* Prompt received */
  671.                             }
  672.                             s++;
  673.                         } else
  674.                             s = string + 1;
  675.                     break;
  676.                 case 2:    /* Line mode */
  677.                     p = buffer;
  678.                     while (count--) {
  679.                         c = *p++ & 0x7F;
  680.                         if (c == '\015') {
  681.                             *string = s - string - 1;
  682.                             StripBS(string);
  683.                             code = FINE;
  684.                             break;    /* Command line received */
  685.                         }
  686.                         if (s <= max)
  687.                             *s++ = c;
  688.                     }
  689.                     break;
  690.             } /* switch (mode) */
  691.         } /* if (count) */
  692.  
  693.         /* Check abort or timeout */
  694.  
  695.         if (Abort)
  696.             code = CANCEL;
  697.         else if (timeout && Ticks > timeout)
  698.             code = TIMEOUT;
  699.  
  700.     } while (code < 0 || Busy);
  701.     /* Only return if no transmission is going on */
  702.     Abort = TRUE;
  703.     return code;
  704. }
  705.  
  706. /* ----- Universal main event loop ------------------------------------- */
  707.  
  708. short LoopBuffer(
  709.     register long timeout,    /* Timeout in ticks (0 for no timeout) */
  710.     register Byte *buffer,    /* Buffer supplied by caller */
  711.     register long limit)    /* Size of buffer */
  712. {
  713.     register long count;        /* Number of characters received */
  714.     register short code = -1;    /* Return code */
  715.     EventRecord event;
  716.  
  717.     if (timeout)
  718.         timeout += Ticks;
  719.     Abort = FALSE;
  720.  
  721.     /* Make sure events and receive buffer are checked at least once */
  722.  
  723.     do {
  724.  
  725.         /* Check for and handle Mac events */
  726.  
  727.         do {
  728.             if (WNE)
  729.                 WaitNextEvent(everyEvent, &event, 0, 0);
  730.             else {
  731.                 SystemTask();
  732.                 GetNextEvent(everyEvent, &event);
  733.             }
  734.             DoEvent(&event);
  735.         } while (Busy);
  736.  
  737.         /* Check receive buffer */
  738.  
  739.         if ((count = SerialCheck()) >= limit) {
  740.             SerialFastRead(buffer, limit);
  741.             AbortCheck(buffer, limit);
  742.             if (Settings.echo)
  743.                 SerialSend(buffer, limit, &Busy);
  744.             if (Settings.save)
  745.                 NewCharacters(buffer, limit, TRUE);
  746.             code = FINE;    /* Buffer received */
  747.         }
  748.  
  749.         /* Check abort or timeout */
  750.  
  751.         if (Abort)
  752.             code = CANCEL;
  753.         else if (timeout && Ticks > timeout)
  754.             code = TIMEOUT;
  755.  
  756.     } while (code < 0 || Busy);
  757.     /* Only return if no transmission is going on */
  758.     Abort = TRUE;
  759.     return code;
  760. }
  761.  
  762. /* ----- Crash --------------------------------------------------------- */
  763.  
  764. pascal void Crash(void)
  765. {
  766.     ExitToShell();
  767. }
  768.  
  769. /* ----- Main ---------------------------------------------------------- */
  770.  
  771. #define STACKSPACE    0x4000    /* We need a least 16K stack (default is 8K on
  772.                                 a Mac Plus and 24K on a Mac IIcx) */
  773.  
  774. void main(void)
  775. {
  776. #ifdef applec
  777.     void _DataInit(void);
  778.     UnloadSeg((Ptr)_DataInit);
  779. #endif
  780.     SetApplLimit(CurStackBase - STACKSPACE);
  781.     MaxApplZone();
  782.     if (Init())
  783.         return;
  784.     UnloadSeg(Init);
  785.     LoadMacros (Settings.scriptVolume, Settings.scriptDirectory,
  786.         MyString(STR_G, G_MACROS));
  787.  
  788.     /* Check if script selected from desktop */
  789.  
  790.     {
  791.         short message, count, i;
  792.         AppFile file;
  793.  
  794.         CountAppFiles(&message, &count);
  795.         if (message == appOpen)
  796.             for (i = 1; i <= count; ++i) {
  797.                 GetAppFiles (i, &file);
  798.                 if (file.fType == TEXT &&
  799.                         CheckSuffix((Byte *)file.fName,
  800.                             MyString(STR_G, G_SUFFIX))) {
  801.                     if (RunScript(file.vRefNum, 0,
  802.                             (Byte *)file.fName, DOSCRIPT))
  803.                         Terminate();
  804.                     break;
  805.                 }
  806.             }
  807.     }
  808.  
  809.     /* Check for startup script */
  810.  
  811.     if (Settings.startName[0] && RunScript(Settings.startVolume,
  812.             Settings.startDirectory, Settings.startName, DOSCRIPT))
  813.         Terminate();
  814.     for (;;) {
  815.         SetWTitle((WindowPtr)TerminalWindow, MyString(STR_G, G_TERMINAL));
  816.         Loop(0, 0, 0);
  817.     }
  818. }
  819.